package cn.manter.basic.service.impl;

import cn.manter.basic.dto.SmsCodeBto;
import cn.manter.basic.constant.BaseConstants;
import cn.manter.basic.exception.BusinessException;
import cn.manter.basic.service.IVerifyCodeService;
import cn.manter.basic.utils.StrUtils;
import cn.manter.basic.utils.VerifyCodeUtils;
import cn.manter.user.domain.User;
import cn.manter.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    private UserMapper userMapper;

    @Override
    public String graph(String key) {
        // 1.判断传递的key值是否为空，
        if(StringUtils.isEmpty(key)){
            throw new BusinessException("请传递必要参数");
        }
        // 2.调用字符串工具类获取四位随机字符串
        String code = StrUtils.getComplexRandomString(4);
        // 3.将随机生成的字符串设置到Redis中，key就是传递进去的key值，并设置过期时间为5分钟
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);
        // 4.将code生成图形并编码成Base64
        String Base64Str = VerifyCodeUtils.VerifyCode(100, 35, code);

        return Base64Str;
    }

    @Override
    public void smsCode(SmsCodeBto smsCodeBto) {
        // 获取短信验证的三个参数
        String phone = smsCodeBto.getPhone();
        String type = smsCodeBto.getType();
        // 非空校验
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空！");
        }
        // 2.判断是走那个业务方法
        // 2.1.注册业务
        if ("register".equals(type)){
            // 校验图形验证码是否正确
            checkImageCode(smsCodeBto);
            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByPhone(phone);
            if (user != null){
                throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY, phone);
        }else if ("binder".equals(type)){ // 2.2.微信绑定账号业务,发送短信验证码
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY, phone);
        }

    }
    /**
    * @Title: checkImageCode
    * @Description: 校验图形验证码
    * @Author: Mr.Zhao
    * @Version: 1.0
    * @Date:  2022/7/10 0010 19:39
    * @Parameters: [smsCodebto]
    * @Return void
    */
    public void checkImageCode(SmsCodeBto smsCodeBto){
        String imageCodeValue = smsCodeBto.getImageCodeValue();
        String imageCodeKey = smsCodeBto.getImageCodeKey();
        // 1.参数判空
        if( StringUtils.isEmpty(imageCodeValue)
            || StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数错误，请输入正确参数");
        }

        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if(imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }

        if(!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue) ){
            throw new BusinessException("参数错误，请输入正确参数");
        }

    }
    /** 
    * @Title: sendCode
    * @Description: 发送手机验证码
    * @Author: Mr.Zhao
    * @Version: 1.0
    * @Date:  2022/7/10 0010 19:37  
    * @Parameters: [businessKey, phone]
    * @Return void
    */
    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);

        // 定义空字符串专门用来接收验证码
        String phoneCode = "";
        if(phoneCodeValue == null){// 不存在
            // 用工具类设置四位数的密码
            phoneCode = StrUtils.getComplexRandomString(4);
        } else{ // 存在
            // 1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 获取过去的时间并转换为Long类型
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 获取当前时间的时间戳
            long nowTime = System.currentTimeMillis();

            if(nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请在一分钟之后获取");
            }
            //将用户的验证码保存到空字符串中
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis =  System.currentTimeMillis()+":"+phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey,phoneCodeRedis,3,TimeUnit.MINUTES);
        // 6.发送短信验证码
        // SmsUtils.sendCode(phone,"亲，你的验证码是"+phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);

    }
}
